package org.wxd.bi.timer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wxd.batis.EntityField;
import org.wxd.batis.query.AppendEnum;
import org.wxd.batis.query.QueryWhere;
import org.wxd.batis.query.WhereEnum;
import org.wxd.batis.sql.SqlEntityTable;
import org.wxd.batis.sql.SqlQueryBuilder;
import org.wxd.batis.sql.mysql.MysqlDataHelper;
import org.wxd.bi.api.po.count.RoleRRData;
import org.wxd.bi.api.po.count.UserRRData;
import org.wxd.bi.api.po.pushlog.LoginRoleLog;
import org.wxd.bi.api.po.pushlog.LoginUserLog;
import org.wxd.bi.api.struct.CountData;
import org.wxd.bi.api.struct.PushColumn;
import org.wxd.bi.data.AppFactory;
import org.wxd.bi.data.AppService;
import org.wxd.str.StringUtil;
import org.wxd.timer.TimeUtil;
import org.wxd.timer.ann.Scheduled;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author: Troy.Chen(無心道, 15388152619)
 * @version: 2021-09-30 15:05
 **/
@Resource
public class CountTimeJob {
    private static final long serialVersionUID = 1L;
    private static final Logger log = LoggerFactory.getLogger(AppService.class);

    private boolean printLog = false;
    @Resource
    private AppFactory appFactory;

    public SqlQueryBuilder where(MysqlDataHelper dataHelper, Class<?> clazz) throws Exception {
        long startTime = TimeUtil.startTimeOffDay(-40);
        long endTime = TimeUtil.currentTimeMillis();
        SqlQueryBuilder sqlQueryBuilder = new SqlQueryBuilder(dataHelper.getDataWrapper());
        sqlQueryBuilder.from(clazz);
        QueryWhere queryWhere = sqlQueryBuilder.newQueryWhere();
        queryWhere.append(PushColumn.SAVE_TIME.getName(), WhereEnum.GteAndLte, startTime, endTime);
        queryWhere.append(AppendEnum.AND, PushColumn.CREATE_TIME.getName(), WhereEnum.GteAndLte, startTime, endTime);
        sqlQueryBuilder.where(null, queryWhere);
        return sqlQueryBuilder;
    }

    @Scheduled(name = "定时统计", value = "0 */10")
    public void count() throws Exception {
        final Map<Integer, AppService> dataServiceMap = appFactory.getDataServiceMap();
        for (AppService appService : dataServiceMap.values()) {
            loginCount(appService.getAppDataHelper());
            roleCount(appService.getAppDataHelper());
        }

    }

    public void loginCount(MysqlDataHelper dataHelper) throws Exception {
        SqlQueryBuilder queryBuilder = where(dataHelper, LoginUserLog.class);
        List<LoginUserLog> loginUserLogs = dataHelper.queryEntities(LoginUserLog.class, queryBuilder);
        Map<String, CountData> map = new LinkedHashMap<>();
        for (LoginUserLog loginUserLog : loginUserLogs) {
            String createDayString = TimeUtil.formatDateString(TimeUtil.SDF_YYYYMMDD, loginUserLog.getCreateTime());
            String loginDayString = TimeUtil.formatDateString(TimeUtil.SDF_YYYYMMDD, loginUserLog.getSaveTime());

            CountData e1 = map.computeIfAbsent(loginDayString, l -> new CountData());
            e1.addLogin(loginUserLog.getUserId());

            CountData createDay = map.computeIfAbsent(createDayString, l -> new CountData());
            createDay.addRR(loginUserLog.getUserId(), loginUserLog.getCreateTime(), loginUserLog.getSaveTime());
        }
        SqlEntityTable sqlEntityTable = dataHelper.asEntityTable(UserRRData.class);
        LinkedHashMap<String, EntityField> columnMap = sqlEntityTable.getColumnMap();
        StringBuilder stringBuilder = null;
        if (printLog) {
            stringBuilder = new StringBuilder();
            for (EntityField value : columnMap.values()) {
                stringBuilder.append(StringUtil.padRight(value.getColumnComment(), 10, ' ') + "\t| ");
            }
            stringBuilder.append("\n");
        }
        for (Map.Entry<String, CountData> dataEntry : map.entrySet()) {
            String dayString = dataEntry.getKey();
            CountData countData = dataEntry.getValue();

            UserRRData rrData = new UserRRData();
            rrData.setDateString(dayString);
            rrData.setLoginCount(countData.getLoginSet().size() + "");

            if (printLog) {
                stringBuilder.append(StringUtil.padRight(dayString, 10, ' ') + "\t| ");
                stringBuilder.append(StringUtil.padRight(countData.getLoginSet().size(), 10, ' ') + "\t| ");
            }

            Map<String, Set<Long>> rr = countData.getRr();
            int r1 = 0;
            for (Map.Entry<String, Set<Long>> entry : rr.entrySet()) {
                String key = entry.getKey();
                EntityField columnMapping = columnMap.get(key);
                if (columnMapping == null) continue;
                int size = entry.getValue().size();
                String f = "0%";
                if ("r1".equals(key)) {
                    r1 = size;
                    f = size + "";
                } else {
                    f = (size * 10000 / r1 / 100f) + " %";
                }
                columnMapping.setFieldValue(rrData, f);
                if (printLog) {
                    stringBuilder.append(StringUtil.padRight(f, 10, ' ') + "\t| ");
                }
            }
            if (printLog) {
                stringBuilder.append("\n");
            }
            dataHelper.replace(rrData);
        }
        if (printLog) {
            log.warn(stringBuilder.toString());
        }
    }

    public void roleCount(MysqlDataHelper dataHelper) throws Exception {
        SqlQueryBuilder queryBuilder = where(dataHelper, LoginRoleLog.class);
        List<LoginRoleLog> loginUserLogs = dataHelper.queryEntities(LoginRoleLog.class, queryBuilder);
        Map<Integer, Map<String, CountData>> map = new LinkedHashMap<>();
        for (LoginRoleLog roleLog : loginUserLogs) {
            String createDayString = TimeUtil.formatDateString(TimeUtil.SDF_YYYYMMDD, roleLog.getCreateTime());
            String loginDayString = TimeUtil.formatDateString(TimeUtil.SDF_YYYYMMDD, roleLog.getSaveTime());

            Map<String, CountData> countDataMap = map.computeIfAbsent(roleLog.getServerId(), l -> new LinkedHashMap<>());

            CountData e1 = countDataMap.computeIfAbsent(loginDayString, l -> new CountData());
            e1.addLogin(roleLog.getUserId());

            CountData createDay = countDataMap.computeIfAbsent(createDayString, l -> new CountData());
            createDay.addRR(roleLog.getUserId(), roleLog.getCreateTime(), roleLog.getSaveTime());
        }
        SqlEntityTable sqlEntityTable = dataHelper.asEntityTable(RoleRRData.class);
        LinkedHashMap<String, EntityField> columnMap = sqlEntityTable.getColumnMap();
        StringBuilder stringBuilder = null;
        if (printLog) {
            stringBuilder = new StringBuilder();
            for (EntityField value : columnMap.values()) {
                stringBuilder.append(StringUtil.padRight(value.getColumnComment(), 10, ' ') + "\t| ");
            }
            stringBuilder.append("\n");
        }
        for (Map.Entry<Integer, Map<String, CountData>> mapEntry : map.entrySet()) {
            final Integer serverId = mapEntry.getKey();
            final Map<String, CountData> value = mapEntry.getValue();
            for (Map.Entry<String, CountData> dataEntry : value.entrySet()) {

                String dayString = dataEntry.getKey();
                CountData countData = dataEntry.getValue();

                RoleRRData rrData = new RoleRRData();
                /*这里的空格不能改*/
                rrData.setDateString(dayString + StringUtil.padLeft(serverId, 10, ' '));
                rrData.setServerId(serverId);
                rrData.setLoginCount(countData.getLoginSet().size() + "");

                if (printLog) {
                    stringBuilder.append(StringUtil.padRight(dayString, 10, ' ') + "\t| ");
                    stringBuilder.append(StringUtil.padRight(countData.getLoginSet().size(), 10, ' ') + "\t| ");
                }

                Map<String, Set<Long>> rr = countData.getRr();
                int r1 = 1;
                for (Map.Entry<String, Set<Long>> entry : rr.entrySet()) {
                    String key = entry.getKey();
                    EntityField columnMapping = columnMap.get(key);
                    if (columnMapping == null) continue;
                    int size = entry.getValue().size();
                    String f = "0%";
                    if ("r1".equals(key)) {
                        r1 = size;
                        f = size + "";
                    } else {
                        f = (size * 10000 / r1 / 100f) + " %";
                    }
                    columnMapping.setFieldValue(rrData, f);
                    if (printLog) {
                        stringBuilder.append(StringUtil.padRight(f, 10, ' ') + "\t| ");
                    }
                }
                if (printLog) {
                    stringBuilder.append("\n");
                }
                dataHelper.replace(rrData);
            }
        }
        if (printLog) {
            log.warn(stringBuilder.toString());
        }
    }

    public boolean isPrintLog() {
        return printLog;
    }

    public CountTimeJob setPrintLog(boolean printLog) {
        this.printLog = printLog;
        return this;
    }

}
